﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

namespace iNet.Tasks
{
	/// <summary>
	/// 負責執行工作的執行緒。
	/// </summary>
	public class TaskExecutionThread
	{
		#region 靜態欄位
		[ThreadStatic]
		static TaskExecutionThread _CurrentThread;
		#endregion
		#region 欄位
		volatile bool _Aborting;
		Task _CurrentTask;
		readonly TaskExecutor _Executor;
		volatile TaskExecutionThreadState _State = TaskExecutionThreadState.Idle;
		Thread _Thread;
		#endregion
		#region 建構子
		internal TaskExecutionThread(TaskExecutor executor, bool isBackground)
		{
			_Executor = executor;
			_Thread = new Thread(this.ExecutionProc);
			_Thread.IsBackground = isBackground;
			_Thread.Name = (string.IsNullOrEmpty(executor.Name) ? "<TaskExecutor>" : executor.Name) + "-Thread-" + _Thread.ManagedThreadId;
			_Thread.SetApartmentState(executor.ExecutionThreadApartmentState);
			_Thread.Start(_Thread);
		}
		#endregion
		#region Abort
		internal void Abort()
		{
			_Aborting = true;
		}
		#endregion
		#region CurrentTask
		/// <summary>
		/// 取得目前正在執行的工作。
		/// </summary>
		public Task CurrentTask
		{
			get
			{
				return _CurrentTask;
			}
		}
		#endregion
		#region CurrentThread
		/// <summary>
		/// 取得目前的 TaskExecutionThread。
		/// </summary>
		public static TaskExecutionThread CurrentThread
		{
			get
			{
				return _CurrentThread;
			}
		}
		#endregion
		#region ExecuteTask
		internal bool ExecuteTask(bool waitForTask, TaskPriority? minPriority)
		{
			//取得下一個工作
			Task task = _Executor.GetNextTask(waitForTask, minPriority);
			if (task == null)
			{
				if (waitForTask && _Executor.ExecutionThreadMode == TaskExecutionThreadMode.OnDemand)
					_Aborting = true;
				return false;
			}

			//執行工作
			if (task == null)
				return false;
			this.ExecuteTask(task);

			//完成
			return true;
		}
		void ExecuteTask(Task task)
		{
			//輸出訊息
			if (_Executor.IsDebugLogEnabled)
				this.WriteDebugLog("Start task '{0}' ({1}) by '{2}'", task.Name, task.GetHashCode(), this.Name);

			//紀錄目前工作
			Task currentTask = _CurrentTask;

			//變更狀態
			_State = TaskExecutionThreadState.Executing;

			//引發事件
			TaskEventArgs eventArgs = new TaskEventArgs(task);
			_Executor.RaiseExecutingTask(eventArgs);

			//執行工作
			_CurrentTask = task;
			task.Execute(this);

			//輸出訊息
			if (_Executor.IsDebugLogEnabled)
				this.WriteDebugLog("Stop task '{0}' ({1}) by '{2}'", task.Name, task.GetHashCode(), this.Name);

			//引發事件
			_Executor.RaiseTaskExecuted(eventArgs);

			//恢復之前的工作
			_CurrentTask = currentTask;

			//變更狀態
			if (currentTask == null)
				_State = TaskExecutionThreadState.Idle;
		}
		#endregion
		#region ExecutionProc
		void ExecutionProc(object param)
		{
			//註冊執行緒
			_CurrentThread = this;

			//執行工作
			try
			{
				while (!_Aborting)
					this.ExecuteTask(true, null);
			}
			finally
			{
				//取消註冊執行緒
				_Executor.RemoveThread(this);

				//更新執行緒數量
				_Executor.UpdateThreads();
			}
		}
		#endregion
		#region Executor
		/// <summary>
		/// 取得所屬的 TaskExecutor。
		/// </summary>
		public TaskExecutor Executor
		{
			get
			{
				return _Executor;
			}
		}
		#endregion
		#region IsAborting
		internal bool IsAborting
		{
			get
			{
				return _Aborting;
			}
		}
		#endregion
		#region Join
		internal bool Join(int timeout)
		{
			return _Thread.Join(timeout);
		}
		#endregion
		#region Name
		/// <summary>
		/// 取得執行緒的名稱。
		/// </summary>
		public string Name
		{
			get
			{
				return _Thread.Name;
			}
		}
		#endregion
		#region State
		/// <summary>
		/// 取的執行緒狀態。
		/// </summary>
		public TaskExecutionThreadState State
		{
			get
			{
				return _State;
			}
		}
		#endregion
		#region WriteDebugLog
		internal void WriteDebugLog(string message)
		{
			Debug.WriteLine("[TaskExecutionThread][" + this.Name + "] " + message);
		}
		internal void WriteDebugLog(string format, params object[] args)
		{
			Debug.WriteLine("[TaskExecutionThread][" + this.Name + "] " + string.Format(format, args));
		}
		#endregion
	}
	#region TaskExecutionThreadMode
	/// <summary>
	/// 表示工作執行緒的模式。
	/// </summary>
	public enum TaskExecutionThreadMode
	{
		/// <summary>
		/// 執行緒建立並執行工作完成後，將不會關閉並持續等待下一個可執行的工作。
		/// </summary>
		Persistent,
		/// <summary>
		/// 執行緒建立並執行工作完成後，將於閒置一段時間之後自動關閉。
		/// </summary>
		OnDemand,
	}
	#endregion
	#region TaskExecutionThreadState
	/// <summary>
	/// 表示 TaskExecutionThread 的狀態。
	/// </summary>
	public enum TaskExecutionThreadState
	{
		/// <summary>
		/// 閒置。
		/// </summary>
		Idle,
		/// <summary>
		/// 正在執行工作。
		/// </summary>
		Executing,
	}
	#endregion
}
